4900 #include "types.h"
4901 #include "defs.h"
4902 #include "param.h"
4903 #include "stat.h"
4904 #include "mmu.h"
4905 #include "proc.h"
4906 #include "fs.h"
4907 #include "file.h"
4908 #include "fcntl.h"
4909 
4910 // Fetch the nth word-sized system call argument as a file descriptor
4911 // and return both the descriptor and the corresponding struct file.
4912 static int
4913 argfd(int n, int *pfd, struct file **pf)
4914 {
4915   int fd;
4916   struct file *f;
4917 
4918   if(argint(n, &fd) < 0)
4919     return -1;
4920   if(fd < 0 || fd >= NOFILE || (f=proc->ofile[fd]) == 0)
4921     return -1;
4922   if(pfd)
4923     *pfd = fd;
4924   if(pf)
4925     *pf = f;
4926   return 0;
4927 }
4928 
4929 // Allocate a file descriptor for the given file.
4930 // Takes over file reference from caller on success.
4931 static int
4932 fdalloc(struct file *f)
4933 {
4934   int fd;
4935 
4936   for(fd = 0; fd < NOFILE; fd++){
4937     if(proc->ofile[fd] == 0){
4938       proc->ofile[fd] = f;
4939       return fd;
4940     }
4941   }
4942   return -1;
4943 }
4944 
4945 
4946 
4947 
4948 
4949 
4950 int
4951 sys_dup(void)
4952 {
4953   struct file *f;
4954   int fd;
4955 
4956   if(argfd(0, 0, &f) < 0)
4957     return -1;
4958   if((fd=fdalloc(f)) < 0)
4959     return -1;
4960   filedup(f);
4961   return fd;
4962 }
4963 
4964 int
4965 sys_read(void)
4966 {
4967   struct file *f;
4968   int n;
4969   char *p;
4970 
4971   if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
4972     return -1;
4973   return fileread(f, p, n);
4974 }
4975 
4976 int
4977 sys_write(void)
4978 {
4979   struct file *f;
4980   int n;
4981   char *p;
4982 
4983   if(argfd(0, 0, &f) < 0 || argint(2, &n) < 0 || argptr(1, &p, n) < 0)
4984     return -1;
4985   return filewrite(f, p, n);
4986 }
4987 
4988 int
4989 sys_close(void)
4990 {
4991   int fd;
4992   struct file *f;
4993 
4994   if(argfd(0, &fd, &f) < 0)
4995     return -1;
4996   proc->ofile[fd] = 0;
4997   fileclose(f);
4998   return 0;
4999 }
5000 int
5001 sys_fstat(void)
5002 {
5003   struct file *f;
5004   struct stat *st;
5005 
5006   if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0)
5007     return -1;
5008   return filestat(f, st);
5009 }
5010 
5011 // Create the path new as a link to the same inode as old.
5012 int
5013 sys_link(void)
5014 {
5015   char name[DIRSIZ], *new, *old;
5016   struct inode *dp, *ip;
5017 
5018   if(argstr(0, &old) < 0 || argstr(1, &new) < 0)
5019     return -1;
5020   if((ip = namei(old)) == 0)
5021     return -1;
5022   ilock(ip);
5023   if(ip->type == T_DIR){
5024     iunlockput(ip);
5025     return -1;
5026   }
5027   ip->nlink++;
5028   iupdate(ip);
5029   iunlock(ip);
5030 
5031   if((dp = nameiparent(new, name)) == 0)
5032     goto bad;
5033   ilock(dp);
5034   if(dp->dev != ip->dev || dirlink(dp, name, ip->inum) < 0){
5035     iunlockput(dp);
5036     goto bad;
5037   }
5038   iunlockput(dp);
5039   iput(ip);
5040   return 0;
5041 
5042 bad:
5043   ilock(ip);
5044   ip->nlink--;
5045   iupdate(ip);
5046   iunlockput(ip);
5047   return -1;
5048 }
5049 
5050 // Is the directory dp empty except for "." and ".." ?
5051 static int
5052 isdirempty(struct inode *dp)
5053 {
5054   int off;
5055   struct dirent de;
5056 
5057   for(off=2*sizeof(de); off<dp->size; off+=sizeof(de)){
5058     if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
5059       panic("isdirempty: readi");
5060     if(de.inum != 0)
5061       return 0;
5062   }
5063   return 1;
5064 }
5065 
5066 int
5067 sys_unlink(void)
5068 {
5069   struct inode *ip, *dp;
5070   struct dirent de;
5071   char name[DIRSIZ], *path;
5072   uint off;
5073 
5074   if(argstr(0, &path) < 0)
5075     return -1;
5076   if((dp = nameiparent(path, name)) == 0)
5077     return -1;
5078   ilock(dp);
5079 
5080   // Cannot unlink "." or "..".
5081   if(namecmp(name, ".") == 0 || namecmp(name, "..") == 0){
5082     iunlockput(dp);
5083     return -1;
5084   }
5085 
5086   if((ip = dirlookup(dp, name, &off)) == 0){
5087     iunlockput(dp);
5088     return -1;
5089   }
5090   ilock(ip);
5091 
5092   if(ip->nlink < 1)
5093     panic("unlink: nlink < 1");
5094   if(ip->type == T_DIR && !isdirempty(ip)){
5095     iunlockput(ip);
5096     iunlockput(dp);
5097     return -1;
5098   }
5099 
5100   memset(&de, 0, sizeof(de));
5101   if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
5102     panic("unlink: writei");
5103   if(ip->type == T_DIR){
5104     dp->nlink--;
5105     iupdate(dp);
5106   }
5107   iunlockput(dp);
5108 
5109   ip->nlink--;
5110   iupdate(ip);
5111   iunlockput(ip);
5112   return 0;
5113 }
5114 
5115 static struct inode*
5116 create(char *path, short type, short major, short minor)
5117 {
5118   uint off;
5119   struct inode *ip, *dp;
5120   char name[DIRSIZ];
5121 
5122   if((dp = nameiparent(path, name)) == 0)
5123     return 0;
5124   ilock(dp);
5125 
5126   if((ip = dirlookup(dp, name, &off)) != 0){
5127     iunlockput(dp);
5128     ilock(ip);
5129     if(type == T_FILE && ip->type == T_FILE)
5130       return ip;
5131     iunlockput(ip);
5132     return 0;
5133   }
5134 
5135   if((ip = ialloc(dp->dev, type)) == 0)
5136     panic("create: ialloc");
5137 
5138   ilock(ip);
5139   ip->major = major;
5140   ip->minor = minor;
5141   ip->nlink = 1;
5142   iupdate(ip);
5143 
5144   if(type == T_DIR){  // Create . and .. entries.
5145     dp->nlink++;  // for ".."
5146     iupdate(dp);
5147     // No ip->nlink++ for ".": avoid cyclic ref count.
5148     if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
5149       panic("create dots");
5150   }
5151 
5152   if(dirlink(dp, name, ip->inum) < 0)
5153     panic("create: dirlink");
5154 
5155   iunlockput(dp);
5156   return ip;
5157 }
5158 
5159 int
5160 sys_open(void)
5161 {
5162   char *path;
5163   int fd, omode;
5164   struct file *f;
5165   struct inode *ip;
5166 
5167   if(argstr(0, &path) < 0 || argint(1, &omode) < 0)
5168     return -1;
5169   if(omode & O_CREATE){
5170     if((ip = create(path, T_FILE, 0, 0)) == 0)
5171       return -1;
5172   } else {
5173     if((ip = namei(path)) == 0)
5174       return -1;
5175     ilock(ip);
5176     if(ip->type == T_DIR && omode != O_RDONLY){
5177       iunlockput(ip);
5178       return -1;
5179     }
5180   }
5181 
5182   if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
5183     if(f)
5184       fileclose(f);
5185     iunlockput(ip);
5186     return -1;
5187   }
5188   iunlock(ip);
5189 
5190   f->type = FD_INODE;
5191   f->ip = ip;
5192   f->off = 0;
5193   f->readable = !(omode & O_WRONLY);
5194   f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
5195   return fd;
5196 }
5197 
5198 
5199 
5200 int
5201 sys_mkdir(void)
5202 {
5203   char *path;
5204   struct inode *ip;
5205 
5206   if(argstr(0, &path) < 0 || (ip = create(path, T_DIR, 0, 0)) == 0)
5207     return -1;
5208   iunlockput(ip);
5209   return 0;
5210 }
5211 
5212 int
5213 sys_mknod(void)
5214 {
5215   struct inode *ip;
5216   char *path;
5217   int len;
5218   int major, minor;
5219 
5220   if((len=argstr(0, &path)) < 0 ||
5221      argint(1, &major) < 0 ||
5222      argint(2, &minor) < 0 ||
5223      (ip = create(path, T_DEV, major, minor)) == 0)
5224     return -1;
5225   iunlockput(ip);
5226   return 0;
5227 }
5228 
5229 int
5230 sys_chdir(void)
5231 {
5232   char *path;
5233   struct inode *ip;
5234 
5235   if(argstr(0, &path) < 0 || (ip = namei(path)) == 0)
5236     return -1;
5237   ilock(ip);
5238   if(ip->type != T_DIR){
5239     iunlockput(ip);
5240     return -1;
5241   }
5242   iunlock(ip);
5243   iput(proc->cwd);
5244   proc->cwd = ip;
5245   return 0;
5246 }
5247 
5248 
5249 
5250 int
5251 sys_exec(void)
5252 {
5253   char *path, *argv[20];
5254   int i;
5255   uint uargv, uarg;
5256 
5257   if(argstr(0, &path) < 0 || argint(1, (int*)&uargv) < 0) {
5258     return -1;
5259   }
5260   memset(argv, 0, sizeof(argv));
5261   for(i=0;; i++){
5262     if(i >= NELEM(argv))
5263       return -1;
5264     if(fetchint(proc, uargv+4*i, (int*)&uarg) < 0)
5265       return -1;
5266     if(uarg == 0){
5267       argv[i] = 0;
5268       break;
5269     }
5270     if(fetchstr(proc, uarg, &argv[i]) < 0)
5271       return -1;
5272   }
5273   return exec(path, argv);
5274 }
5275 
5276 int
5277 sys_pipe(void)
5278 {
5279   int *fd;
5280   struct file *rf, *wf;
5281   int fd0, fd1;
5282 
5283   if(argptr(0, (void*)&fd, 2*sizeof(fd[0])) < 0)
5284     return -1;
5285   if(pipealloc(&rf, &wf) < 0)
5286     return -1;
5287   fd0 = -1;
5288   if((fd0 = fdalloc(rf)) < 0 || (fd1 = fdalloc(wf)) < 0){
5289     if(fd0 >= 0)
5290       proc->ofile[fd0] = 0;
5291     fileclose(rf);
5292     fileclose(wf);
5293     return -1;
5294   }
5295   fd[0] = fd0;
5296   fd[1] = fd1;
5297   return 0;
5298 }
5299 
